//
//  TrainingModel.swift
//  MoYoung
//
//  Created by sylar on 17/2/21.
//  Copyright © 2017年 sylar. All rights reserved.
//

import Foundation
import SQLite
import SwiftDate
import HandyJSON
import SQLiteValueExtension
import MapKit
import MYModule

/// 运动 一次运动
open class TrainingModel: NSObject, MYSQLiteTableiabe, HandyJSON {
    
    public var adress: String = ""
    
    public var id: Int64 = 0
    
    public var date: Date = Date().sqlDate()
    
    /// 记录id recordId = 14 是最近的一次运动
    /// 注意： 不要通过recordId 查询，是不准的
    //    public var recordId = 0
    
    /// 开始时间戳(为0 的是无效数据)
    public var startTime: Int = 0
    
    /// 结束时间戳
    public var endTime: Int = 0
    
    /// 1:跑步 4:骑车 8:羽毛球 16:游泳 32:自行车
    public var type: Int = 0
    
    /// 运动时长
    public var vaildTime: Int = 0
    
    /// 步数
    public var step: Int = 0
    
    /// 距离
    public var distance: Int = 0
    
    /// 卡路里
    public var kcal: Int = 0
    
    /// 运动持续心率(10秒一个)
    public var heartRates: [Int] = []
    
    /// 运动持续心率数组最近的更新时间
    public var heartRatesUpdateTime: Double = 0
    
    /// 步数详情
    public var steps: [Int] = []
    
    /// 配速 每一公里用时多少秒
    public var paces: [Int] = []
    
    /// 距离详情
    public var distances: [Int] = []
    
    /// 经纬度
    public var locations: [TrainingLocation] = []
    
    /// 爬升高度
    public var elevation: String = ""
    
    /// 是否在中国
    public var isChina: Bool = true
    
    /// 目标设置类型(goalTime, goalStep, goalDistance, goalKcal目前只有一个有效)
    /// distance = 0
    /// time = 1
    /// pace = 2
    /// calorie = 3
    /// 255 代表无目标设置
    public var goalType: Int = 255
    
    /// 目标数值
    public var goal: Int = 0
    
    /// 目标是否达成
    public var achievement: Bool = false
    
    /// 心率平均数
    public var heartRateAvg: Int = 0
    
    /// 心率地址？？ 
    public var hrAddress: Int = 0
    
    /// 是否同步过设备返回历史记录 1 是同步过
    public var syncRecord: Int = 0
    
    
    /// 开始时间
    public var startDate: Date {
        return Date(seconds: (TimeInterval(startTime)))
        
    }
    
    /// 结束时间
    public var endDate: Date {
        return Date(seconds: (TimeInterval(endTime)))
    }
    
    /// 距离单位
    public let distance_unit = "m"
    
    /// 卡路里单位
    public let calorie_unit = "cal"
    
    /// 时间单位
    public let time_unit = "s"
    
    /// 配速单位
    public let pace_unit = "m/km"
    
    //这条运动数据的运动状态，默认 0：未开始  1： 锻炼中 2： 暂停 
    public var trainingState: Int = 0
    
    
    required public override init() {}
    
    
    public func updateData() {
        
        if self.startTime <= 0 {
            return
        }
        
        if let _ = Self.model(of: type, startTime: self.startTime) {
            
            self.update()
            return
        }
        
        self.insert()
    }
    
    
    /// 一分钟中运动心率最大值最小值
    /// - Parameter date: 日期
    /// - Returns: 元组数组
    public static func flatMapTrainingHeartRateWithMinute(date: Date) ->[(max: Int, min: Int, avg: Int)] {
        
        let allHearts = flatMapTrainingHeartRateWithTenSconds(date: date)
        
        
        var minuteTuples: [(max: Int, min: Int, avg: Int)] = []
        var max: Int = 0
        var min: Int = 255
        
        var minuteAll: Int = 0
        var minuteCount: Int = 0
        
        allHearts.enumerated().forEach { i, h in
            
            if max < h && h > 0 {
                max = h
            }
            if min > h && h > 0 {
                min = h
            }
            if h > 0 {
                minuteCount += 1
                minuteAll += h
            }
            
            if (i + 1)%6 == 0 {
                
                if min > max {
                    min = max
                }
                var avg = 0
                if minuteCount > 0 {
                    avg = Int(minuteAll/minuteCount)
                }
                
                let tuple = (max, min, avg)
                minuteTuples.append(tuple)
                max = 0
                min = 255
                minuteAll = 0
                
            }
            
        }
        
        // 尾部扫尾
        if max > 0 || min < 255 {
            
            if min > max {
                min = max
            }
            var avg = 0
            if minuteCount > 0 {
                avg = Int(minuteAll/minuteCount)
            }
            let tuple = (max, min, avg)
            minuteTuples.append(tuple)
        }
        
       
        return minuteTuples
    }
    
    
    /// 一天运动心率拆成每半小时的平均值
    /// - Parameter date: 日期
    /// - Returns: []
    public static func flatMapAvgTrainingHeartRateWithHalfHour(date: Date) ->[Int] {
        
        let allHeart = flatMapTrainingHeartRateWithTenSconds(date: date)
        
        // 每180个放一个数组
        var rangeArr: [Int] = []
        var avgs: [Int] = []
        
        allHeart.enumerated().forEach { i, e in
            
            if (i + 1)%180 == 0 {
                
                let arr = rangeArr.filter({ $0 > 0 })
                var avg = 0
                if !arr.isEmpty {
                    let total = arr.reduce(0, { $0 + $1 })
                    avg = total/arr.count
                }
                avgs.append(avg)
                rangeArr.removeAll()
            }
            rangeArr.append(e)
            
        }
        
        return avgs
        
    }
    
    /// 一天运动心率拆成每10秒钟的数据
    /// - Parameter date: 日期
    /// - Returns: []
    public static func flatMapTrainingHeartRateWithTenSconds(date: Date) ->[Int] {
        
        let count = 1440 * 6
        var allHearts = (0 ..< count).map { _ in 0 }
        guard let trainModels =  [TrainingModel].deserialize(from: date) else {
            return allHearts
        }
        
        
        trainModels.forEach {
            
            let start = $0.startTime
            let startTimeDate = Date(timeIntervalSince1970: TimeInterval(start))
            
            let today = Int(startTimeDate.dateAtStartOf(.day).timeIntervalSince1970)
            
            let currentIndex = (start - today)/10
            
           
            $0.heartRates.enumerated().forEach { i, h in
                let index = currentIndex + i
                allHearts[index] = h
                
            }
        }
        
        return allHearts
        
    }
    
    public static func model(of type: Int, startTime: Int) ->TrainingModel? {
        
        let expression_type = Expression<Int>("type")
        let expression_startTime = Expression<Int>("startTime")
        
        let query = self.table.where(expression_type == type).where(expression_startTime == startTime)
        // 首先查询准确 startTime 是否在数据库存在
        guard let row = try? self.db.pluck(query) else {
            
            // 不存在查询全天过滤 type，得到最近的一次运动
            let date = Date(timeIntervalSince1970: TimeInterval(startTime))
            let all = [TrainingModel].deserialize(from: date)
            var models = all?.filter({ $0.type == type })
            models = models?.sorted(by: { m1, m2 in
                return m1.startTime > m2.startTime
            })
            
            // 时间差 60秒内的就算是同一个
            return models?.filter({
                abs($0.startTime - startTime) <= 60
            }).first
            
        }
        let model = TrainingModel.deserialize(from: row)
        return model
    }
    
    /// 一次新的运动
    /// - Parameter type: 类型
    /// - Returns: model
    public static func newTraining(type: Int) ->TrainingModel {
        let model = TrainingModel()
        model.startTime = Int(Date().timeIntervalSince1970)
        model.type = type
        model.adress = DeviceInfo.current().adress ?? ""
        
        return model
        //既然都是新的运动，为什么还要去查endtime和type??
//        let expression_type = Expression<Int>("type")
//        let expression_endTime = Expression<Int>("endTime")
//
//        let query = self.table.filter(expression_type == type).where(expression_endTime == 0)
//        let row = try? self.db.pluck(query)
//
//        guard let model = TrainingModel.deserialize(from: row) else {
//
//            let model = TrainingModel()
//            model.startTime = Int(Date().timeIntervalSince1970)
//            model.type = type
//            model.mac = DeviceInfo.current().mac ?? ""
//
//            return model
//        }
//        model.type = type
//        model.startTime = Int(Date().timeIntervalSince1970)
//        model.mac = DeviceInfo.current().mac ?? ""
        
        return model
        
    }
    
    
    /// 最近的运动（根据类型查询及目标设置类型查询）
    /// - Parameter type: 类型
    /// - Returns: model
    public static func last(type: Int, _ goalType: Int? = nil, startTime: Int? = nil) ->TrainingModel? {
        
        let expression_type = Expression<Int>("type")
        
        var query = TrainingModel.table.where(expression_type == type)
        if let goalType = goalType {
            let expression_goalType = Expression<Int>("goalType")
            query = query.where(expression_goalType == goalType)
        }
        
        if let startTime = startTime {
            let expression_startTime = Expression<Int>("startTime")
            query = query.where(expression_startTime == startTime)
        }
        
        let rows = try? self.db.prepare(query)
        
        // 这个类型全部的数据
        let all = [TrainingModel].deserialize(from: rows)
        
        // 按时间排序
        let models = all.sorted(by: { m1, m2 in
            return m1.startTime > m2.startTime
        })
        
        return models.first
    }
    
    
    public static func models(of type: Int) ->[TrainingModel] {
        
        let expression_type = Expression<Int>("type")
        let query = TrainingModel.table.filter(expression_type == type)
        
        let rows = try? self.db.prepare(query)
        let models = [TrainingModel].deserialize(from: rows)
        return models
        
    }
    
}


extension CLLocationCoordinate2D: HandyJSON {}

/// 经纬度
public struct TrainingLocation: StringValueExpressible, HandyJSON {
    
    public init() {}
    
    
    public var latitude: CLLocationDegrees = 0
    
    public var longitude: CLLocationDegrees = 0
    /// 海拔高度，可以是正的 可以是负的
    public var altitude: CLLocationDistance = 0
    
    public var horizontalAccuracy: CLLocationAccuracy = 0
    
    public var verticalAccuracy: CLLocationAccuracy = 0
    
    /// 日期时间戳
    public var times: Double = 0
    
    /// 速度 负数表示无效
    public var speed: CLLocationSpeed = -1
    
    /// 航向
    public var course: CLLocationDirection = -1
    
    public var clLocation: CLLocation? {
        return CLLocation.initWith(trainingLocation: self)
    }
    
    
    public init(location: CLLocation) {
        
        self.latitude = location.coordinate.latitude
        self.longitude = location.coordinate.longitude
        self.altitude = location.altitude
        self.horizontalAccuracy = location.horizontalAccuracy
        self.verticalAccuracy = location.verticalAccuracy
        self.times = location.timestamp.timeIntervalSince1970
        self.speed = location.speed
        self.course = location.course
        
        
    }
    
    public static func fromStringValue(_ stringValue: String) -> TrainingLocation {
        
        return TrainingLocation.deserialize(from: stringValue) ?? TrainingLocation()
    }
    
    public var stringValue: String {
        let jsonStr = self.toJSONString() ?? ""
        
        print("location = \(jsonStr)")
        return jsonStr
    }
    
}

extension CLLocation {
    
    public static func initWith(trainingLocation: TrainingLocation) ->CLLocation {
        
        let coordinate = CLLocationCoordinate2D(latitude: trainingLocation.latitude, longitude: trainingLocation.longitude)
        let altitude = trainingLocation.altitude
        let horizontalAccuracy = trainingLocation.horizontalAccuracy
        let verticalAccuracy = trainingLocation.verticalAccuracy
        let course = trainingLocation.course
        let speed = trainingLocation.speed
        let timestamp = Date(timeIntervalSince1970: trainingLocation.times)
        
        return CLLocation(coordinate: coordinate, altitude: altitude, horizontalAccuracy: horizontalAccuracy, verticalAccuracy: verticalAccuracy, course: course, speed: speed, timestamp: timestamp)
    }
    
}



